package com.example.springkotlindemo.controller

import com.example.springkotlindemo.entity.DemoUser
import com.example.springkotlindemo.model.AjaxResult
import kotlinx.coroutines.Dispatchers.Unconfined
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.reactive.asFlow
import kotlinx.coroutines.reactor.awaitSingle
import kotlinx.coroutines.reactor.mono
import org.springframework.data.domain.Sort
import org.springframework.data.relational.core.query.Update
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.r2dbc.core.applyAndAwait
import org.springframework.data.r2dbc.core.usingAndAwait
import org.springframework.data.relational.core.query.Criteria.where
import org.springframework.data.relational.core.query.Query.query
import org.springframework.web.bind.annotation.*
import javax.annotation.Resource
import reactor.core.publisher.Mono

/**
 * @author Xu Haidong
 * @date 2023/4/24 10:48
 */
@RestController
@RequestMapping("/demoUser")
class DemoUserController {

    @Resource
    private lateinit var template: R2dbcEntityTemplate

    @GetMapping("/query/{id}")
    fun query(@PathVariable id: Long): Mono<AjaxResult> = mono(Unconfined) {
        AjaxResult.success(
            data = template.select(DemoUser::class.java).from(DemoUser.tableName).matching(
                query(where("user_id").`is`(id))
            ).one().asFlow().first()
        )
    }

    @GetMapping("/listAll")
    fun listAll(): Mono<AjaxResult> = mono(Unconfined) {
        AjaxResult.success(
            data = template.select(DemoUser::class.java).from(DemoUser.tableName).matching(
                query(where("user_id").greaterThan(1L)).sort(Sort.by(Sort.Order.desc("create_time")))
            ).all().asFlow().toList()
        )
    }

    @PostMapping
    fun save(@RequestBody demoUser: DemoUser): Mono<AjaxResult> = mono(Unconfined) {
        if (null == demoUser.userId) {
            template.insert(DemoUser::class.java).into(DemoUser.tableName).usingAndAwait(demoUser)
        } else {
            val update = Update.update("nickName", demoUser.nickName).set("userName", demoUser.userName)
            template.update(DemoUser::class.java).inTable(DemoUser.tableName).matching(
                query(where("user_id").`is`(demoUser.userId!!))
            ).applyAndAwait(update)
        }
        AjaxResult.success()
    }

    @DeleteMapping("/remove/{id}")
    fun delete(@PathVariable id: Long): Mono<AjaxResult> = mono(Unconfined) {
        template.delete(DemoUser::class.java).from(DemoUser.tableName).matching(
            query(where("user_id").`is`(id))
        ).all().awaitSingle()
        AjaxResult.success()
    }

}